#pragma once
#include<iostream>
#include"Col.h"
#include"Row.h"
using namespace std;

class TableOperator{
private:

    static void checkTransaction(const Transaction* transaction){
        if(transaction == nullptr){throw string("transaction cannot be null");}
    }

    static void checkIncludeAllCol(const TableInfo* tableInfo, const map<string, vector<Basic*>>& colDatas){
        if(tableInfo->getColCount() != colDatas.size()){
            throw string("Not all columns were added");
        }
    }

    static void checkLegalColName(const TableInfo* tableInfo, const map<string, vector<Basic*>>& colDatas){
        for(const auto& it : colDatas){
            tableInfo->getColInfo(it.first);    //没有对应的ColInfo会抛异常
        }
    }

    static void checkColDataSameSize(const map<string, vector<Basic*>>& colDatas){
        const size_t& size = colDatas.begin()->second.size();
        for(const auto& it : colDatas){
            if(size != it.second.size()){
                throw string("The number of column data should be consistent");
            }
        }
    }

    static map<string, Basic*> rowsDataToRowData(const map<string, vector<Basic*>>& rowsData){
        map<string, Basic*> rowData;
        for(const auto& it : rowsData){
            rowData[it.first] = it.second.front();
        }
        return rowData;
    }

    static void createTableDirectory(const TableInfo* tableInfo){
        const string& tableFullPath = ResourceInfo::getTableFullPath(tableInfo->getBaseName(), tableInfo->getTableName());
        const vector<string>& colNameVec = tableInfo->getColNameVec(false);
        for(const string& colName : colNameVec){
            IOUtil::createDirectory(tableFullPath + "\\" + colName);
        }
        IOUtil::createDirectory(tableFullPath + "\\blockDel");
    }

public:
    //数据定义
    static ColInfo* defAndGetColInfo(const string& colName, const TYPE& dataType, const bool& isWithIndex, const vector<double>& rangeLeft){
        return new ColInfo(colName, dataType, isWithIndex, rangeLeft);
    }

    static ColInfo* defAndGetColInfo(const string& colName, const TYPE& dataType, const bool& isWithIndex, const double& leftInterval, const double& rightInterval, const int& partitionCount){
        return new ColInfo(colName, dataType, isWithIndex, leftInterval, rightInterval, partitionCount);
    }

    static void tableInfoDef(const string& baseName, const string& tableName, const int16_t& blockCount, const vector<ColInfo*>& colInfoVec){
        TableInfo* tableInfo = new TableInfo(baseName, tableName, blockCount, colInfoVec);
        TableInfoManager::putTableInfo(tableInfo);
        createTableDirectory(tableInfo);
    }

    //数据读取
    static map<string, vector<Basic*>> currentReadRowsData(const string& baseName, const string& tableName, const vector<string>& colNameVec, const map<int16_t, set<int>>& mergeSortLocInfo, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return RowOperator::currentReadRowsData(tableInfo, colNameVec, mergeSortLocInfo, lockType, transaction);
    }

    static map<string, vector<Basic*>> snapShotReadRowsData(const string& baseName, const string& tableName, const vector<string>& colNameVec, const map<int16_t, set<int>>& mergeSortLocInfo){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return RowOperator::snapShotReadRowsData(tableInfo, colNameVec, mergeSortLocInfo);
    }

    static map<string, Basic*> currentReadRowData(const string& baseName, const string& tableName, const vector<string>& colNameVec, const LocInfo& locInfo, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        const map<string, vector<Basic*>>& rowsData = currentReadRowsData(baseName, tableName, colNameVec, LocInfoUtil::locInfoToMergeSortLocInfo({locInfo}), lockType, transaction);
        return rowsDataToRowData(rowsData);
    }

    static map<string, Basic*> snapShotReadRowData(const string& baseName, const string& tableName, const vector<string>& colNameVec, const LocInfo& locInfo){
        const map<string, vector<Basic*>>& rowsData = snapShotReadRowsData(baseName, tableName, colNameVec, LocInfoUtil::locInfoToMergeSortLocInfo({locInfo}));
        return rowsDataToRowData(rowsData);
    }

    static map<int16_t, set<int>> currentGetUnDelLocInfo(const string& baseName, const string& tableName, const map<int16_t, set<int>>& mergeSortLocInfo, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return RowOperator::currentGetUnDelLocInfo(tableInfo, mergeSortLocInfo, lockType, transaction);
    }

    static map<int16_t, set<int>> snapShotGetUnDelLocInfo(const string& baseName, const string& tableName, const map<int16_t, set<int>>& mergeSortLocInfo){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return RowOperator::snapShotGetUnDelLocInfo(tableInfo, mergeSortLocInfo);
    }

    //数据搜索
    static map<int16_t, set<int>> currentDataSearch(const string& baseName, const string& tableName, const string& colName, const vector<Basic*>& targetDataVec, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return ColOperator::currentDataSearch(tableInfo, colName, targetDataVec, lockType, transaction);
    }

    static map<int16_t, set<int>> snapShotDataSearch(const string& baseName, const string& tableName, const string& colName, const vector<Basic*>& targetDataVec){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return ColOperator::snapShotDataSearch(tableInfo, colName, targetDataVec);
    }

    static map<int16_t, set<int>> currentHigherRangeDataSearch(const string& baseName, const string& tableName, const string& colName, Basic* targetData, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return ColOperator::currentHigherRangeDataSearch(tableInfo, colName, targetData, lockType, transaction);
    }

    static map<int16_t, set<int>> snapShotHigherRangeDataSearch(const string& baseName, const string& tableName, const string& colName, Basic* targetData){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return ColOperator::snapShotHigherRangeDataSearch(tableInfo, colName, targetData);
    }

    static map<int16_t, set<int>> currentLowerRangeDataSearch(const string& baseName, const string& tableName, const string& colName, Basic* targetData, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return ColOperator::currentLowerRangeDataSearch(tableInfo, colName, targetData, lockType, transaction);
    }

    static map<int16_t, set<int>> snapShotLowerRangeDataSearch(const string& baseName, const string& tableName, const string& colName, Basic* targetData){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return ColOperator::snapShotLowerRangeDataSearch(tableInfo, colName, targetData);
    }

    static map<int16_t, set<int>> currentCeilingRangeDataSearch(const string& baseName, const string& tableName, const string& colName, Basic* targetData, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return ColOperator::currentCeilingRangeDataSearch(tableInfo, colName, targetData, lockType, transaction);
    }

    static map<int16_t, set<int>> snapShotCeilingRangeDataSearch(const string& baseName, const string& tableName, const string& colName, Basic* targetData){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return ColOperator::snapShotCeilingRangeDataSearch(tableInfo, colName, targetData);
    }

    static map<int16_t, set<int>> currentFloorRangeDataSearch(const string& baseName, const string& tableName, const string& colName, Basic* targetData, const LOCKTYPE& lockType, Transaction* transaction = nullptr){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return ColOperator::currentFloorRangeDataSearch(tableInfo, colName, targetData, lockType, transaction);
    }

    static map<int16_t, set<int>> snapShotFloorRangeDataSearch(const string& baseName, const string& tableName, const string& colName, Basic* targetData){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        return ColOperator::snapShotFloorRangeDataSearch(tableInfo, colName, targetData);
    }

    //数据操作
    static void addRowsData(const string& baseName, const string& tableName, const map<string, vector<Basic*>>& addDatas, Transaction* transaction){
        checkTransaction(transaction);  //数据操作事务不应为null
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        checkIncludeAllCol(tableInfo, addDatas);    //加一行数据应包含所有列
        checkLegalColName(tableInfo, addDatas);     //操作数据的所有列都应为合法列
        checkColDataSameSize(addDatas);             //操作数据的所有列都应相同大小
        RowOperator::addRowsData(tableInfo, addDatas, transaction);
    }

    static void delRowsData(const string& baseName, const string& tableName, const map<int16_t, set<int>>& mergeSortLocInfo, Transaction* transaction){
        checkTransaction(transaction);  //数据操作事务不应为null
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        RowOperator::delRowsData(tableInfo, mergeSortLocInfo, transaction);
    }

    static void modRowsData(const string& baseName, const string& tableName, const map<int16_t, set<int>>& mergeSortLocInfo, const map<string, vector<Basic*>>& modDatas, Transaction* transaction){
        checkTransaction(transaction);  //数据操作事务不应为null
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        checkLegalColName(tableInfo, modDatas);     //操作数据的所有列都应为合法列
        checkColDataSameSize(modDatas);             //操作数据的所有列都应相同大小
        RowOperator::modRowsData(tableInfo, mergeSortLocInfo, modDatas, transaction);
    }


};
